/**
 *  (c)
 * <p>
 *
 * <p>
 *
 */

package com.nn.smart.bus.service.impl;

import com.nn.smart.bus.async.UserDeptTask;
import com.nn.smart.bus.common.token.dto.DeptDataScopeDTO;
import com.nn.smart.bus.common.token.dto.WorkUserAuthorizationDTO;
import com.nn.smart.bus.common.token.dto.WorkUserAuthorizationScripDTO;
import com.nn.smart.bus.commons.tools.log.SysLogLogin;
import com.nn.smart.bus.commons.tools.log.enums.LogTypeEnum;
import com.nn.smart.bus.commons.tools.log.enums.LoginOperationEnum;
import com.nn.smart.bus.commons.tools.log.enums.LoginStatusEnum;
import com.nn.smart.bus.commons.tools.log.producer.LogProducer;
import com.nn.smart.bus.commons.tools.security.user.UserDetail;
import com.nn.smart.bus.dto.AuthorizationDTO;
import com.nn.smart.bus.dto.LoginDTO;
import com.nn.smart.bus.feign.UserFeignClient;
import com.nn.smart.bus.jwt.JwtProperties;
import com.nn.smart.bus.jwt.JwtUtils;
import com.nn.smart.bus.service.AuthService;
import com.nn.smart.bus.commons.tools.constant.NumConstant;
import com.nn.smart.bus.commons.tools.exception.ErrorCode;
import com.nn.smart.bus.commons.tools.exception.NNException;
import com.nn.smart.bus.commons.tools.redis.RedisKeys;
import com.nn.smart.bus.commons.tools.redis.RedisUtils;
import com.nn.smart.bus.commons.tools.redis.UserDetailRedis;
import com.nn.smart.bus.commons.tools.security.enums.UserKillEnum;
import com.nn.smart.bus.commons.tools.security.password.PasswordUtils;
import com.nn.smart.bus.commons.tools.security.user.SecurityUser;
import com.nn.smart.bus.commons.tools.utils.ConvertUtils;
import com.nn.smart.bus.commons.tools.utils.HttpContextUtils;
import com.nn.smart.bus.commons.tools.utils.IpUtils;
import com.nn.smart.bus.commons.tools.utils.Result;
import com.nn.smart.bus.dto.DataScopeDeptList;
import com.nn.smart.bus.dto.SysUserOpenIdFormDTO;
import com.nn.smart.bus.enums.UserStatusEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.List;

/**
 * 认证服务
 *
 * @author nanning
 * @since 1.0.0
 */
@Service
public class AuthServiceImpl implements AuthService {
    @Autowired
    private UserFeignClient userFeignClient;
    @Autowired
    private UserDetailRedis userDetailRedis;
    @Autowired
    private LogProducer logProducer;
    @Autowired
    private JwtUtils jwtUtils;
    @Autowired
    private JwtProperties jwtProperties;

    @Autowired
    private UserDeptTask userDeptTask;

    @Autowired
    private RedisUtils redisUtils;

    @Override
    public AuthorizationDTO login(LoginDTO login) {
        HttpServletRequest request = HttpContextUtils.getHttpServletRequest();

        //获取用户信息
        Result<UserDetail> result = userFeignClient.getByUsername(login.getUsername());
        UserDetail user = result.getData();

        //登录日志
        SysLogLogin log = new SysLogLogin();
        log.setType(LogTypeEnum.LOGIN.value());
        log.setOperation(LoginOperationEnum.LOGIN.value());
        log.setCreateDate(new Date());
        log.setIp(IpUtils.getIpAddr(request));
        log.setUserAgent(request.getHeader(HttpHeaders.USER_AGENT));
        log.setIp(IpUtils.getIpAddr(request));

        //账号不存在
        if (user == null) {
            log.setStatus(LoginStatusEnum.FAIL.value());
            log.setCreatorName(login.getUsername());
            logProducer.saveLog(log);

            throw new NNException(ErrorCode.ACCOUNT_PASSWORD_ERROR);
        }

        //密码错误
        if (!PasswordUtils.matches(login.getPassword(), user.getPassword())) {
            log.setStatus(LoginStatusEnum.FAIL.value());
            log.setCreator(user.getId());
            log.setCreatorName(user.getUsername());
            logProducer.saveLog(log);

            throw new NNException(ErrorCode.ACCOUNT_PASSWORD_ERROR);
        }

        //账号停用
        if (user.getStatus() == UserStatusEnum.DISABLE.value()) {
            log.setStatus(LoginStatusEnum.LOCK.value());
            log.setCreator(user.getId());
            log.setCreatorName(user.getUsername());
            logProducer.saveLog(log);

            throw new NNException(ErrorCode.ACCOUNT_DISABLE);
        }

        //保存到Redis
        userDetailRedis.set(user, jwtProperties.getExpire());

        //登录成功，生成token
        String token = jwtUtils.generateToken(user.getId());

        //授权信息
        AuthorizationDTO authorization = new AuthorizationDTO();
        authorization.setToken(token);
        authorization.setExpire(jwtProperties.getExpire());

        //登录用户信息
        log.setCreator(user.getId());
        log.setCreatorName(user.getUsername());
        log.setStatus(LoginStatusEnum.SUCCESS.value());
        logProducer.saveLog(log);

        userDeptTask.packageUserDeptOptions(user.getId());

        return authorization;
    }

    @Override
    public Result<WorkUserAuthorizationDTO> workLogin(String username, String password) {
        HttpServletRequest request = HttpContextUtils.getHttpServletRequest();

        //获取用户信息
        Result<UserDetail> result = userFeignClient.getByUsername(username);
        UserDetail user = result.getData();

        //授权信息
        WorkUserAuthorizationDTO authorization = new WorkUserAuthorizationDTO();

        //登录日志
        SysLogLogin log = new SysLogLogin();
        log.setType(LogTypeEnum.LOGIN.value());
        log.setOperation(LoginOperationEnum.LOGIN.value());
        log.setCreateDate(new Date());
        log.setIp(IpUtils.getIpAddr(request));
        log.setUserAgent(request.getHeader(HttpHeaders.USER_AGENT));
        log.setIp(IpUtils.getIpAddr(request));

        //账号不存在
        if (user == null) {
            log.setStatus(LoginStatusEnum.FAIL.value());
            log.setCreatorName(username);
            logProducer.saveLog(log);
            authorization.setRegisterState(NumConstant.ZERO_STR);
            return new Result<WorkUserAuthorizationDTO>().error("用户名或密码错误");
        }

        //密码错误
        if (null != password && !PasswordUtils.matches(password, user.getPassword())) {
            log.setStatus(LoginStatusEnum.FAIL.value());
            log.setCreator(user.getId());
            log.setCreatorName(user.getUsername());
            logProducer.saveLog(log);

            return new Result<WorkUserAuthorizationDTO>().error("用户名或密码错误");
        }

        //账号停用
        if (user.getStatus() == UserStatusEnum.DISABLE.value()) {
            log.setStatus(LoginStatusEnum.LOCK.value());
            log.setCreator(user.getId());
            log.setCreatorName(user.getUsername());
            logProducer.saveLog(log);
            return new Result<WorkUserAuthorizationDTO>().error("账号已停用");
        }

        //保存到Redis
        userDetailRedis.set(user, jwtProperties.getExpire());

        //登录成功，生成token
        String token = jwtUtils.generateToken(user.getId());

        authorization.setToken(token);
        authorization.setExpire(jwtProperties.getExpire());

        //登录用户信息
        log.setCreator(user.getId());
        log.setCreatorName(user.getUsername());
        log.setStatus(LoginStatusEnum.SUCCESS.value());
        logProducer.saveLog(log);

        // 获取用户所有角色权限信息
        List<DataScopeDeptList> dataScopeDeptList = this.getDataScopeDetailList(user.getId());
        authorization.setDeptDataScopeList(ConvertUtils.sourceToTarget(dataScopeDeptList, DeptDataScopeDTO.class));

        authorization.setDeptName(user.getDeptName());
        authorization.setUserTagKey(user.getTypeKey());
        authorization.setRegisterState(NumConstant.ONE_STR);

        userDeptTask.packageUserDeptOptions(user.getId());

        return new Result<WorkUserAuthorizationDTO>().ok(authorization);
    }

    @Override
    public void logout(Long userId) {
        HttpServletRequest request = HttpContextUtils.getHttpServletRequest();

        UserDetail user = SecurityUser.getUser();

        //退出日志
        SysLogLogin log = new SysLogLogin();
        log.setType(LogTypeEnum.LOGIN.value());
        log.setOperation(LoginOperationEnum.LOGOUT.value());
        log.setIp(IpUtils.getIpAddr(request));
        log.setUserAgent(request.getHeader(HttpHeaders.USER_AGENT));
        log.setIp(IpUtils.getIpAddr(request));
        log.setStatus(LoginStatusEnum.SUCCESS.value());
        log.setCreator(user.getId());
        log.setCreatorName(user.getUsername());
        log.setCreateDate(new Date());
        logProducer.saveLog(log);

        userDetailRedis.logout(userId);
    }

    @Override
    public List<DataScopeDeptList> getDataScopeDetailList(Long id) {
        Result<List<DataScopeDeptList>> result = userFeignClient.getDataScopeList(id);
        if (result.success()) {
            return result.getData();
        }

        return null;
    }

    @Override
    public Result modifyOpenId(SysUserOpenIdFormDTO sysUserOpenIdFormDto) {
        return userFeignClient.modifyOpenIdByUsername(sysUserOpenIdFormDto);
    }

    /**
     * 退出登录
     * @param userId
     * @Author nanning
     */
    @Override
    public Result logoutUser(Long userId) {
        // 清空redis
        String key = RedisKeys.getSecurityUserKey(userId);
        redisUtils.hSet(key, "kill", UserKillEnum.YES.value());

        // 更新open_id
        userFeignClient.updateUserOpenId(userId);

        return new Result();


    }

    @Override
    public Result<WorkUserAuthorizationScripDTO> workScripLogin(String scrip) {
        HttpServletRequest request = HttpContextUtils.getHttpServletRequest();

        //获取用户信息
        Result<UserDetail> result = userFeignClient.getByScrip(scrip);
        UserDetail user = result.getData();

        //授权信息
        WorkUserAuthorizationDTO authorization = new WorkUserAuthorizationDTO();

        //登录日志
        SysLogLogin log = new SysLogLogin();
        log.setType(LogTypeEnum.LOGIN.value());
        log.setOperation(LoginOperationEnum.LOGIN.value());
        log.setCreateDate(new Date());
        log.setIp(IpUtils.getIpAddr(request));
        log.setUserAgent(request.getHeader(HttpHeaders.USER_AGENT));
        log.setIp(IpUtils.getIpAddr(request));

        //账号不存在
        if (user == null) {
            log.setStatus(LoginStatusEnum.FAIL.value());
            log.setCreatorName(scrip);
            logProducer.saveLog(log);
            authorization.setRegisterState(NumConstant.ZERO_STR);
            return new Result<WorkUserAuthorizationScripDTO>().error("未根据凭证获取到用户");
        }

        //账号停用
        if (user.getStatus() == UserStatusEnum.DISABLE.value()) {
            log.setStatus(LoginStatusEnum.LOCK.value());
            log.setCreator(user.getId());
            log.setCreatorName(user.getUsername());
            logProducer.saveLog(log);
            return new Result<WorkUserAuthorizationScripDTO>().error("账号已停用");
        }

        //保存到Redis
        userDetailRedis.set(user, jwtProperties.getExpire());

        //登录成功，生成token
        String token = jwtUtils.generateToken(user.getId());

        authorization.setToken(token);
        authorization.setExpire(jwtProperties.getExpire());

        //登录用户信息
        log.setCreator(user.getId());
        log.setCreatorName(user.getUsername());
        log.setStatus(LoginStatusEnum.SUCCESS.value());
        logProducer.saveLog(log);

        // 获取用户所有角色权限信息
        List<DataScopeDeptList> dataScopeDeptList = this.getDataScopeDetailList(user.getId());
        authorization.setDeptDataScopeList(ConvertUtils.sourceToTarget(dataScopeDeptList, DeptDataScopeDTO.class));

        authorization.setDeptName(user.getDeptName());
        authorization.setUserTagKey(user.getTypeKey());
        authorization.setRegisterState(NumConstant.ONE_STR);

        userDeptTask.packageUserDeptOptions(user.getId());
        WorkUserAuthorizationScripDTO workUserAuthorizationScripDTO = new WorkUserAuthorizationScripDTO();
        workUserAuthorizationScripDTO.setWorkUserAuthorizationDTO(authorization);
        workUserAuthorizationScripDTO.setUsername(user.getUsername());
        return new Result<WorkUserAuthorizationScripDTO>().ok(workUserAuthorizationScripDTO);
    }
}
